/*
 * button.c
 *
 *  Created on: Dec 30, 2023
 *      Author: tangle
 */

#include "driver_button.h"

Button *head_handle;

/**
* @name   Button_Attach
* @brief  注册回调函数函数
* @param  handle: 按键句柄结构体
* @param  pin_level: 按钮状态 0:未按下 1:按下.
* @param  cb: 按钮事件处理回调函数.
* @param  event: 按键初始事件类型
* @retval None
*/
void button_attach(Button* handle,uint8_t(*pin_level)(),BtnCallback cb,PressEvent event)
{
    memset(handle, 0, sizeof(struct Button));
    handle->event = (uint8_t)event;//默认按键未按下
    handle->hal_button_Level = pin_level;//注册读取按键电平函数
    handle->button_level = handle->hal_button_Level();//读取按键电平
    handle->cb = cb;//注册回调函数

    /* start the button */
    button_start( handle );
}


/**
* @name   Get_Button_Event
* @brief  按键获取事件
* @param  按键结构体
* @retval 事件类型
*/
PressEvent get_button_event(Button* handle)
{
    return (PressEvent)(handle->event);
}

/**
* @name   Button_Handler
* @brief  按键处理状态机函数
* @param  按键句柄
* @retval None
*/
void button_handler(struct Button* handle)
{
    uint8_t read_gpio_level = handle->hal_button_Level();

    /* 计时器计时 */
    if((handle->state) > 0)
    {
        handle->ticks++;
    }

    /* 消抖 */
    if(read_gpio_level != handle->button_level)
    {
        if(++(handle->debounce_cnt) >= DEBOUNCE_TICKS)
        {
            handle->button_level = read_gpio_level;
            handle->debounce_cnt = 0;
        }
    }
    else
    {
        handle->debounce_cnt = 0;
    }

    handle->event = read_gpio_level;

    /*状态机*/
    switch (handle->state) {
    case 0:
        if(handle->button_level == BTN_PRESSED)
        {
            handle->event |= (uint8_t)PRESS_DOWN;
            EVENT_CB(PRESS_DOWN);
            handle->ticks = 0;
            handle->repeat = 1;
            handle->state = 1;
        }
        else
        {
            handle->event |= (uint8_t)BTN_UNPRESS;
        }
        break;

    case 1:
        if(handle->button_level != BTN_PRESSED)
        {
            handle->event |= (uint8_t)PRESS_UP;
            EVENT_CB(PRESS_UP);
            handle->ticks = 0;
            handle->state = 2;

        }
        else if(handle->ticks > LONG_TICKS)
        {
            handle->event |= (uint8_t)LONG_RRESS_START;
            EVENT_CB(LONG_RRESS_START);
            handle->state = 5;
        }
        break;

    case 2:
        if(handle->button_level == BTN_PRESSED)
        {
            handle->event |= (uint8_t)PRESS_DOWN;
            EVENT_CB(PRESS_DOWN);
            handle->repeat++;
            if(handle->repeat == 2)
            {
                EVENT_CB(DOUBLE_CLICK);
            }
            EVENT_CB(PRESS_REPEAT);
            handle->ticks = 0;
            handle->state = 3;
        }
        else if(handle->ticks > SHORT_TICKS)
        {
            if(handle->repeat == 1) {
                handle->event |= (uint8_t)SINGLE_CLICK;
                EVENT_CB(SINGLE_CLICK);
            }
            else if(handle->repeat == 2)
            {
                handle->event |= (uint8_t)DOUBLE_CLICK;
            }
            handle->state = 0;
        }
        break;

    case 3:
        if(handle->button_level != BTN_PRESSED)
        {
            handle->event |= (uint8_t)PRESS_UP;
            EVENT_CB(PRESS_UP);
            if(handle->ticks < SHORT_TICKS) {
                handle->ticks = 0;
                handle->state = 2;
            }
            else
            {
                handle->state = 0;
            }
        }
        break;

    case 5:
        if(handle->button_level == BTN_PRESSED)
        {
            handle->event |= (uint8_t)LONG_PRESS_HOLD;
            EVENT_CB(LONG_PRESS_HOLD);

        } else
        {
            handle->event |= (uint8_t)PRESS_UP;
            EVENT_CB(PRESS_UP);
            handle->state = 0;
        }
        break;
    }
}

/**
* @name   Button_Start
* @brief  启动按钮工作，将句柄添加到工作列表中。
* @param  按键结构体
* @retval 0: 成功. -1: 句柄已存在.
*/
int8_t button_start(Button* handle)
{
    struct Button* target = head_handle;
    /*按键初始化的时候 head_handle=NULL
    * 判断任务句柄是否为空
    */
    while(target)
    {
        /*判断任务句柄是否重复*/
        if(target == handle)
            return -1;	//already exist.
        //句柄移动，直到为NULL
        target = target->next;
    }
    handle->next = head_handle;
    head_handle = handle;
    return 0;
}

/**
* @name   Button_Stop
* @brief  按键停止检测
* @param  按键结构体
* @retval None
*/
void button_stop(Button* handle)
{
    struct Button** curr;
    for(curr = &head_handle; *curr; )
    {
        struct Button* entry = *curr;
        if (entry == handle)
        {
            *curr = entry->next;
//          free(entry);
        } else
            curr = &entry->next;
    }
}

/**
* @name   Button_Ticks
* @brief  运行函数，放在循环或者定时中断里运行
* @param  None.
* @retval None
*/
void button_ticks()
{
    Button* target;
    for(target=head_handle; target; target=target->next)
    {
        button_handler(target);
    }
}
